#region

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Reflection;
using CommandLineMapper.Helpers;
using CommandLineMapper.Interfaces;

#endregion

namespace CommandLineMapper {
    public class ObjectMapper : IObjectMapper {
        private readonly IPropertyHandlerFactory _propertyHandlerFactory = new PropertyHandlerFactory();
        #region Implementation of IObjectMapper

        public IObjectMappingResult Map(object instance, NameValueCollection collection) {
            AssertUtils.AssertArgumentNull(instance, "instance");
            AssertUtils.AssertArgumentNull(collection, "collection");
            AssertUtils.AssertArgument(collection.Count == 0, "collection is empty");
            IList<IPropertyHandler> propertyHandlers = GetPropertyHandlers(instance);
            if(propertyHandlers.Count == 0) {
                return new ObjectMappingResult(collection.AllKeys);
            }
            return HandleProperties(instance, collection, propertyHandlers);
        }

        private static IObjectMappingResult HandleProperties(object instance, NameValueCollection collection, IList<IPropertyHandler> propertyHandlers) {
            IObjectMappingResult result = new ObjectMappingResult(collection.AllKeys);

            foreach (string s in collection.Keys) {
                if (String.IsNullOrEmpty(collection[s])) {
                    continue;
                }

                string key = s;
                foreach (IPropertyHandler propertyHandler in propertyHandlers) {
                    if(!propertyHandler.IsKeyMatch(key)) {
                        continue;
                    }
                    propertyHandler.SetValue(instance, collection[key]);
                }
            }

            return result;
        }


        #endregion

        private IList<IPropertyHandler> GetPropertyHandlers(object instance) {
            IList<IPropertyHandler> propertyHandlers 
                = GetProperties(instance)
                    .Select(propertyInfo => 
                        _propertyHandlerFactory.Create(propertyInfo))
                            .Where(propertyHandler => propertyHandler != null).ToList();
            return propertyHandlers;
        }

        private static IEnumerable<PropertyInfo> GetProperties(object instance) {
            return instance.GetType().GetProperties();
        }

    }
}